package com.rr.mymoney.model;

import java.io.Serializable;
import java.util.Date;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.JoinTable;
import javax.persistence.ManyToMany;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.SequenceGenerator;
import javax.persistence.Table;
import javax.persistence.UniqueConstraint;

import com.rr.mymoney.model.enums.TransactionType;

@Entity
@Table(name = "transactions")
@SequenceGenerator(name = "transactions_seq", sequenceName = "transactions_seq")
public class Transaction implements Serializable {

    private static final long serialVersionUID = -5240487623199720268L;

    private Long id;
    private Account account;
    private Float value;
    private TransactionType type;
    private Date date;
    private String details;
    private User user;
    private Category category;
    private List<Tag> tags;
    private List<Transaction> subTransactions;
    private Transaction parentTransaction;
    private boolean ignoreInReports;

    @Id
    @GeneratedValue(generator = "transactions_seq", strategy = GenerationType.AUTO)
    public Long getId() {
	return id;
    }

    public void setId(Long id) {
	this.id = id;
    }

    @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinColumn(name = "account_id")
    public Account getAccount() {
	return account;
    }

    public void setAccount(Account account) {
	this.account = account;
    }

    @Column(name = "value", nullable = false, columnDefinition = "decimal(14,4)")
    public Float getValue() {
	return value;
    }

    public void setValue(Float value) {
	this.value = value;
    }

    @Column(name = "type", nullable = false)
    public TransactionType getType() {
	return type;
    }

    public void setType(TransactionType type) {
	this.type = type;
    }

    @Column(name = "date")
    public Date getDate() {
	return date;
    }

    public void setDate(Date date) {
	this.date = date;
    }

    @Column(name = "details", length = 1000)
    public String getDetails() {
	return details;
    }

    public void setDetails(String details) {
	this.details = details;
    }

    @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinColumn(name = "user_id", nullable = false)
    public User getUser() {
	return user;
    }

    public void setUser(User user) {
	this.user = user;
    }

    @ManyToOne(cascade = { CascadeType.MERGE })
    @JoinColumn(name = "category_id")
    public Category getCategory() {
	return category;
    }

    public void setCategory(Category category) {
	this.category = category;
    }

    @ManyToMany(targetEntity = Tag.class, cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinTable(name = "transactions_tags", joinColumns = { @JoinColumn(name = "transaction_id") }, inverseJoinColumns = { @JoinColumn(name = "tag_id") }, uniqueConstraints = { @UniqueConstraint(columnNames = {
	    "transaction_id", "tag_id" }) })
    @OrderBy("name")
    public List<Tag> getTags() {
	return tags;
    }

    public void setTags(List<Tag> tags) {
	this.tags = tags;
    }

    /**
     * @return the subTransactions
     */
    @OneToMany(cascade = { CascadeType.PERSIST, CascadeType.MERGE }, targetEntity = Transaction.class, mappedBy = "parentTransaction")
    public List<Transaction> getSubTransactions() {
	return subTransactions;
    }

    /**
     * @param subTransactions
     *            the subTransactions to set
     */
    public void setSubTransactions(List<Transaction> subTransactions) {
	this.subTransactions = subTransactions;
    }

    /**
     * @return the parentTransaction
     */
    @ManyToOne(cascade = { CascadeType.PERSIST, CascadeType.MERGE })
    @JoinColumn(name = "parent_transaction_id")
    public Transaction getParentTransaction() {
	return parentTransaction;
    }

    /**
     * @param parentTransaction
     *            the parentTransaction to set
     */
    public void setParentTransaction(Transaction parentTransaction) {
	this.parentTransaction = parentTransaction;
    }

    /**
     * @return the ignoreInReports
     */
    @Column(name = "ignore_in_reports", nullable = false, columnDefinition = "tinyint(1)")
    public boolean isIgnoreInReports() {
	return ignoreInReports;
    }

    /**
     * @param ignoreInReports
     *            the ignoreInReports to set
     */
    public void setIgnoreInReports(boolean ignoreInReports) {
	this.ignoreInReports = ignoreInReports;
    }

    /* (non-Javadoc)
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
	StringBuilder builder = new StringBuilder();
	builder.append("Transaction [id=").append(id).append(", value=").append(value).append(", date=").append(date).append(", ignore=").append(ignoreInReports).append(", account=").append(account.getName());
	if (category != null) {
	    builder.append(", category=").append(category.getName());
	}
	builder.append("]");
	return builder.toString();
    }
}
